use ntex::web::{self, types::{Json, State, Path}, Responder};
use std::sync::Arc;
use crate::{errors::CustomError, models::{article::{Article, ArticlePreview}, user::Admin}, AppState};
use sqlx::Row;

//获取文章预览 返回文字标题和创建时间
#[web::get("/articles_preview")]
pub async fn get_articles_preview(
        state: State<Arc<AppState>>
) -> Result<Json<Vec<ArticlePreview>>, CustomError> {
    let db_pool = &state.db_pool;

    let articles = sqlx::query("SELECT id, title, created_at FROM articles")
        .fetch_all(db_pool)
        .await?
        .iter()
        .map(|row| ArticlePreview {
            id: row.get("id"),
            title: row.get("title"),
            created_at: row.get("created_at"),
        })
        .collect::<Vec<ArticlePreview>>();

    Ok(Json(articles))
}

//通过id获取文章
#[web::get("/article/{id}")]
pub async fn get_article(
    id: Path<(u32,)>,
    state: State<Arc<AppState>>,
) -> Result<Json<Article>, CustomError> {
    let db_pool = &state.db_pool;

    let article = sqlx::query_as::<_, Article>("SELECT * FROM articles WHERE id = ?")
        .bind(id.0)
        .fetch_one(db_pool)
        .await?;

    Ok(Json(article))
}


//添加文章
#[web::post("/add_article")]
pub async fn new_article(
    // _: Admin,
    Json(article): Json<Article>,
    state: State<Arc<AppState>>,
) -> Result<impl Responder, CustomError> {
    let db_pool = &state.db_pool;

    sqlx::query(
        "INSERT INTO articles (title, content) VALUES (?, ?)",
    )
    .bind(article.title)
    .bind(article.content)
    .execute(db_pool)
    .await?;

    Ok(ntex::web::HttpResponse::Created().body("Article added successfully"))
}

//更新文章
#[web::put("/update_article")]
pub async fn update_article(
    Json(article): Json<Article>,
    state: State<Arc<AppState>>,
) -> Result<impl Responder, CustomError> {
    let db_pool = &state.db_pool;

    let id = match article.id {
        Some(id) => id,
        None => {
            return Err(CustomError::BadRequest("Article ID is required to update".into()));
        }
    };

    sqlx::query("UPDATE articles SET title = $1, content = $2 WHERE id = $3")
        .bind(&article.title)
        .bind(&article.content)
        .bind(id)
        .execute(db_pool)
        .await?;

    Ok(ntex::web::HttpResponse::Accepted().body("Article updated successfully"))
}

//删除文章
#[web::delete("/delete_article/{id}")]
pub async fn delete_article(
    // id: Path<(u32,)>,
    id: Path<u32>,
    state: State<Arc<AppState>>,
) -> Result<String, CustomError> {
    let db_pool = &state.db_pool;
    let t:u32 = id.into_inner();

    sqlx::query("DELETE FROM articles WHERE id = ?")
        .bind(t)
        .execute(db_pool)
        .await?;

    Ok("Article deleted successfully".into())
}


//搜索文章  /articles/search/{keyword}
pub async fn serach_article(
    keyword: Path<(String,)>,
    state: State<Arc<AppState>>,
) -> Result<Json<Vec<ArticlePreview>>, CustomError> {
    let db_pool = &state.db_pool;

    let result = sqlx::query(
        "SELECT id, title, created_at FROM articles WHERE title LIKE ? OR content LIKE ?"
    )
    .bind(format!("%{}%", keyword.0))
    .bind(format!("%{}%", keyword.0))
    .fetch_all(db_pool)
    .await?
    .iter()
    .map(|row| ArticlePreview {
        id: row.get("id"),
        title: row.get("title"),
        created_at: row.get("created_at"),
    })
    .collect::<Vec<ArticlePreview>>();

    if result.is_empty() {
        return Err(CustomError::NotFound("No articles found".into()));
    }

    Ok(Json(result))
}